#pragma once

#include <iostream>
#include <stdarg.h>
#include <iostream>
#include <string>
#include <cstdarg>
#include <ctime>
#include <unistd.h>
#include <fstream>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>

#define Size 1024

namespace ns_log
{
    enum
    {
        Debug = 0,
        Info,
        Warning,
        Error,
        Fatal,
    };

    enum
    {
        Screen = 10,
        OneFile,
        ClassFile
    };

    std::string LevelToString(int level)
    {
        switch (level)
        {
        case Debug:
            return "Debug";
        case Info:
            return "Info";
        case Warning:
            return "Warning";
        case Error:
            return "Error";
        case Fatal:
            return "Fatal";
        default:
            return "Unknown";
        }
    }

    const int defaultstyle = Screen;
    const std::string default_filename = "log.";
    const std::string logdir = "log";

    class Log
    {
    private:
        int Style; // 日志输出
        std::string filename;

    public:
        Log() : Style(defaultstyle), filename(default_filename)
        {
            // 创建默认的日志存放路径
            mkdir(logdir.c_str(), 0775);
        }
        ~Log() {}

        void Enable(int Style)
        {
            this->Style = Style;
        }

        std::string TimeStampExlocalTime() // 获取时间
        {
            time_t currtime = time(nullptr);
            struct tm *curr = localtime(&currtime); // localtime
            char time_buffer[128];
            snprintf(time_buffer, sizeof time_buffer, "%d-%d-%d %d:%d:%d",
                     curr->tm_year + 1900, curr->tm_mon + 1, curr->tm_mday, curr->tm_hour, curr->tm_min, curr->tm_sec);
            return time_buffer;
        }

        // 写一个日志文件
        void WriteLogOneFile(const std::string &logname, const std::string &loginfo)
        {
            umask(0);
            int fd = open(logname.c_str(), O_CREAT | O_WRONLY | O_APPEND, 0666);
            if (fd < 0)
            {
                std::cout << "open error!" << std::endl;
                return;
            }

            write(fd, loginfo.c_str(), loginfo.size());
            close(fd);

            // std::ofstream out(logname);
            // if(!out.is_open())
            // return;
            // out.write(loginfo.c_str(),loginfo.size());
            // out.close();
        }

        // 写一组日志文件
        void WriteLogToClassFile(const std::string &levelstr, const std::string &loginfo)
        {
            // 将日志放在指定路径下
            //  logdir 默认路径 "log"
            std::string logname = logdir + '/' + filename + levelstr;
            WriteLogOneFile(logname, loginfo);
        }

        // 以一定的形式写文件
        void WriteLog(const std::string &levelstr, const std::string &loginfo)
        {
            switch (Style)
            {
            case Screen:
                std::cout << loginfo;
                break;
            case OneFile:
                WriteLogToClassFile("all", loginfo);
                break;
            case ClassFile:
                WriteLogToClassFile(levelstr, loginfo);
                break;
            default:
                break;
            }
        }

        // 集成日志信息
        void LogMessage(int level, const char *format, ...)
        {
            std::string levelstr = LevelToString(level);   // 消息等级
            std::string currtime = TimeStampExlocalTime(); // 时间
            std::string idstr = std::to_string(getpid());  // 进程ID

            char rightbuffer[Size];
            va_list args;
            va_start(args, format);
            vsnprintf(rightbuffer, sizeof rightbuffer, format, args); // format 用户定义的格式进行初始化
            va_end(args);

            char leftbuffer[Size];
            snprintf(leftbuffer, sizeof leftbuffer, "[%s][%s][%s]",
                     levelstr.c_str(), currtime.c_str(), idstr.c_str());

            std::string loginfo = leftbuffer;
            loginfo += rightbuffer;
            WriteLog(levelstr, loginfo);

            // std::cout<<leftbuffer<<std::endl;

            // uint64_t currtime = time(nullptr);
            //  std::string currtime = TimeStampExlocalTime();
            //  printf("[%s][%s]%s\n", LevelToString(level).c_str(),
            //  currtime.c_str(),content);
            /* printf("[%s][%s]%s\n", LevelToString(level).c_str(),
            std::to_string(currtime).c_str(),content); */
        }
    };

    Log lg;

    class Conf
    {
    public:
        Conf()
        {
            lg.Enable(Screen); // 调整日志打印位置   OneFile, ClassFile  Screen
        }
        ~Conf()
        {
        }
    };

    Conf conf;

}